home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ian & Stuart's Australian Mac 1
/
Ian and Stuart's One (Australia).iso
/
Australasian Legends
/
Commercial
/
Rainbow Hill
/
MacDOS™ 2.0.0
/
filters
/
filter projects
/
speakOut.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-06-13
|
7KB
|
227 lines
// speakOut.c uses the Speech Manager to speak out the messages.
//
// 94/06/12 File created
// 94/06/13 First version completed
//
//--------------------------------------------------------------------------------------------------
// Copyright © 1994 by Rainbow Hill Pty Ltd.
//
// This program is free software; you can redistribute it and/or modify it under the terms of
// the GNU General Public License as published by the Free Software Foundation; either version 2
// of the License, or any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with this program;
// if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <Errors.h>
#include <Events.h>
#include <Speech.h>
#include <GestaltEqu.h>
#include "pipe.h"
static SpeechChannel chan;
static pipeParmsFun_t HandleParameters;
main() {
OSErr os_err;
unsigned char buff[pipeSize];
EventRecord keyboardPollEvent;
// Mac Toolbox initialisation
MaxApplZone();
InitGraf(&thePort);
InitWindows();
InitDialogs(0L);
InitCursor();
// initialise the incoming pipe
PipeInit(HandleParameters);
// keep getting records from the master as long as no error occurs
while (true) {
// wait to receive the next record
PipePoll(buff);
// speak up
os_err = SpeakText(chan, (Ptr)&buff[1], (long)buff[0]);
if (os_err != noErr) PipeReportError(os_err, nil);
while (SpeechBusy() > 0) {
if (
WaitNextEvent(keyDownMask, &keyboardPollEvent, 0L, nil)
&&
PipeIsBreak_M(keyboardPollEvent)
)
PipeReportError(userCanceledErr, nil);
}
// keep MacDOS happy by sending an empty message
*buff = '\0';
PipeSendData(buff);
}
} // main
//--------------------------------------------------------------------------------- HandleParameters
static OSErr HandleParameters(unsigned char *p) {
typedef enum {
idleState, // between parameters
slashState, // slash found
optionState, // option found
numState // assembling a number
} state_t;
short k;
state_t s;
char opt;
unsigned char aNum[8]; // 7 characters are plenty!
long aLong;
OSErr err;
short voiceCount;
VoiceSpec voice;
Fixed pitch;
Fixed rate;
short voiceID;
short pitchIncr;
short speed;
long result;
// check that we have speech
err = Gestalt(gestaltSpeechAttr, &result);
if (err != noErr || (result & (1 << gestaltSpeechMgrPresent)) == 0)
PipeReportError(pipeFilteringErr, "\pSpeech Manager not available");
//
// Three parameters are supported:
// /P to increment or decrement the voice pitch (default: 0)
// /S to set the speed of the speech in words per minute (default: use system default)
// /V use a voice ID (default: use system default)
//
// In any case, the format is /Xy, where 'y' is an integer number, possibly including a
// plus or minus unary sign.
//
// The parameters come in any order, in upper or lower case, and separated by single
// spaces.
//
// add a space at the end to simplify the analysis (there should be space available!)
p[0]++;
p[p[0]] = '\0';
// initialise the speech parameters
voiceID = 0;
pitchIncr = 0;
speed = 0;
// scan the parameter list to update the speech parameters if necessary
s = idleState;
for (k = 1; k <= p[0]; k++) {
switch (s) {
case idleState:
if (p[k] != '\0') {
if (p[k] != '/')
PipeReportError(pipeFilteringErr, "\pAll parameters must begin with a slash");
s = slashState;
}
break;
case slashState:
opt = p[k];
if (opt >= 'a' && opt <= 'z') opt -= 'a' - 'A';
if (opt != 'P' && opt != 'S' && opt != 'V')
PipeReportError(pipeFilteringErr, "\pOnly options P, S, and V supported");
s = optionState;
break;
case optionState:
if (p[k] != '\0') {
if ((p[k] < '0' || p[k] > '9') && p[k] != '-' && p[k] != '+')
PipeReportError(pipeFilteringErr, "\pA number must follow the option code");
aNum[0] = 1;
aNum[1] = p[k];
s = numState;
}
break;
case numState:
if (p[k] == '\0') {
StringToNum(aNum, &aLong);
if (opt == 'V')
voiceID = aLong;
else if (opt == 'P')
pitchIncr = aLong;
else if (opt == 'S')
speed = aLong;
s = idleState;
}
else {
if (aNum[0] >= 7 || p[k] < '0' || p[k] > '9')
PipeReportError(pipeFilteringErr, "\pBad parameter");
aNum[0]++;
aNum[aNum[0]] = p[k];
}
break;
default:
PipeReportError(pipeFilteringErr, "\pBad character in parameter");
}
}
//
// initialise the speech manager
//
// check whether the user requires a particular voice
if (voiceID == 0) {
// No particular voice is requested. Check how many voices are available.
err = CountVoices(&voiceCount);
if (err != noErr) PipeReportError(pipeFilteringErr, "\pNo voices available");
// grab the first voice which can be successfully identified
err = pipeFilteringErr;
for (k = 1; k <= voiceCount && err != noErr; k++)
err = GetIndVoice(k, &voice);
if (err != noErr) PipeReportError(pipeFilteringErr, "\pNo voices actually available");
}
else {
// the user requests a particular voice
err = GetIndVoice(voiceID, &voice);
if (err != noErr) PipeReportError(pipeFilteringErr, "\pRequested voice not available");
}
// open a new channel (it will be disposed of when the application quits)
err = NewSpeechChannel(&voice, &chan);
if (err != noErr) PipeReportError(pipeFilteringErr, "\pNo speech channel available");
// check whether we have to update the speech rate
if (speed != 0) {
err = GetSpeechRate(chan, &rate);
if (err != noErr) PipeReportError(pipeFilteringErr, "\pSpeech rate unobtainable");
rate = (long)speed * 0x10000L;
err = SetSpeechRate(chan, rate);
if (err != noErr) PipeReportError(pipeFilteringErr, "\pSpeech rate cannot be set");
}
// check whether we have to change the pitch
if (pitchIncr != 0) {
err = GetSpeechPitch(chan, &pitch);
if (err != noErr) PipeReportError(pipeFilteringErr, "\pPitch unobtainable");
pitch += (long)pitchIncr * 0x60000L;
err = SetSpeechPitch(chan, pitch);
if (err != noErr) PipeReportError(pipeFilteringErr, "\pPitch cannot be set");
}
RETURN_LBL:
return (noErr);
} // HandleParameters